class Zvue{
    constructor(options){
        this.$el = document.querySelector(options.el);
        this.$data  = options.data;
        this.Observe(this.$data)
        this.Complie(this.$el)
    }
    Observe(obj){
        if (typeof obj !== "object" || obj === null) {
            return;
        }
        this.Reactive(obj)
    }
    Reactive(data){
        for (const key in data) {
            this.Observe(data[key])
            let dep = new Dep();
            let val = data[key]
            Object.defineProperty(this.$data,key,{
                get(){
                    if (Dep.target) {
                        dep.addSubs(Dep.target)
                    }
                    return val
                },
                set(newVal){
                    if (newVal === val) return
                    val = newVal;
                    dep.notify()
                }
            })
        }
    }

    Complie(el){
        let nodes = el.children
        for (let i = 0; i < nodes.length; i++) {
           let node = nodes[i];
           if (node.children.length>0) {
               this.Complie(node)
           }
           if (node.hasAttribute('v-text')) {
               let attrValue = node.getAttribute('v-text');
               new Watcher(node,this,attrValue,'innerHTML')
           }
           if (node.hasAttribute('v-model')) {
                let attrValue = node.getAttribute('v-model');
                new Watcher(node,this,attrValue,'value')
                node.addEventListener('input',(e)=>{
                    this.$data[attrValue] = node.value
                })
           }
        }
    }
    // 这个是将$data数据挂载到vm上 现在不需要
    proxy(vm) {
        Object.keys(vm.$data).forEach(key => {
          Object.defineProperty(vm, key, {
            get() {
              return vm.$data[key]
            },
            set(v) {
              vm.$data[key] = v
            }
          })
        })
      }
}
class Dep{
    target = null 
    constructor(){
        this.subdeps = [];
    }
    addSubs(watcher){
        this.subdeps.push(watcher);
    }
    notify(){
        this.subdeps.forEach(watcher=>{
            watcher.upDate();
        })
    }
}
class Watcher{
    constructor(node,vm,attrValue,attr){
        this.node = node;
        this.vm = vm;
        this.attrValue = attrValue
        this.attr = attr
        this.get();
        this.upDate()
    }
    get(){
        Dep.target = this;
        this.vm.$data[this.attrValue];
        Dep.target = null;
    }
    upDate(){
        this.node[this.attr] = this.vm.$data[this.attrValue]
    }
}
export default Zvue

// Webpack 的运行流程是一个串行的过程，从启动到结束会依次执行以下流程：
// 初始化参数：从配置文件和 Shell 语句中读取与合并参数，得出最终的参数；
// 开始编译：用上一步得到的参数初始化 Compiler 对象，加载所有配置的插件，执行对象的 run 方法开始执行编译；
// 确定入口：根据配置中的 entry 找出所有的入口文件；
// 编译模块：从入口文件出发，调用所有配置的 Loader 对模块进行翻译，再找出该模块依赖的模块，再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理；
// 完成模块编译：在经过第4步使用 Loader 翻译完所有模块后，得到了每个模块被翻译后的最终内容以及它们之间的依赖关系；
// 输出资源：根据入口和模块之间的依赖关系，组装成一个个包含多个模块的 Chunk，再把每个 Chunk 转换成一个单独的文件加入到输出列表，这步是可以修改输出内容的最后机会；
// 输出完成：在确定好输出内容后，根据配置确定输出的路径和文件名，把文件内容写入到文件系统。
// 在以上过程中，Webpack 会在特定的时间点广播出特定的事件，插件在监听到感兴趣的事件后会执行特定的逻辑，并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

// 用我自己的话说
// webpack执行的过程其实就是一个串行的过程
// 1.初始化参数，从配置文件等拿到需要的参数
// 2.开始编译：这个时候根据这些参数去这个编译程序的实例，加载所有的配置插件
// 3.根据entry 找到文件的入口
// 4.从入口出发，根据配置的loader进行对模块的一个处理，我们知道webpack原生只对js的支持，所以这样通过loader进行翻译，递归查找所有进行处理
// 5.模块编译完成：我们可以得到了最终的模块的内容和他们之间的依赖关系
// 6.输出资源：这些依赖关系和入口模块 组装成一个个的chunk代码块，然后再把这些代码块转换成文件加入输出列表
// 在以上过程中，Webpack 会在特定的时间点广播出特定的事件，插件在监听到感兴趣的事件后会执行特定的逻辑，并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
